package cn.xinfei.xdecision.data.core.frame.executors.http;

import cn.xinfei.xdecision.common.model.datax.enums.ExecutorType;
import cn.xinfei.xdecision.common.model.datax.enums.MqDeliveryScene;
import cn.xinfei.xdecision.common.model.datax.exception.XDecisionDataException;
import cn.xinfei.xdecision.common.model.datax.exception.XDecisionDataExceptionType;
import cn.xinfei.xdecision.common.utils.util.OKHttpClientManage;
import cn.xinfei.xdecision.common.utils.util.runner.DictVariableUtils;
import cn.xinfei.xdecision.data.core.vo.VarInterfaceInfoVO;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;

import java.net.SocketTimeoutException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Component
public class HttpExecutorClient {

    private static final Logger LOGGER = LoggerFactory.getLogger(HttpExecutorClient.class);
    private static final String DATA_TRANSFER_VAR_KEY = "element_id_list";
    private static final String DATA_TRANSFER_VAR_CONTEXT_KEY = "context";

    private OKHttpClientManage okHttpClientManage = null;



    public Map<String, Object> postVirtualDataTransferResponse(VarInterfaceInfoVO interfaceInfo, Set<String> varCodes, Map<String, Object> varContextMap) {
        String requestUrl = interfaceInfo.getUrl();
        if (StringUtils.isBlank(requestUrl)) {
            LOGGER.error("requestUrl is null,please check interfaceId : {} config", interfaceInfo.getId());
            return null;
        }
        Integer connectTimeout = interfaceInfo.getConnectTimeout();
        Integer readTimeout = interfaceInfo.getReadTimeout();
        okHttpClientManage = OKHttpClientManage.getOkHttpClientManage(requestUrl, connectTimeout, readTimeout);
        // 取差集，去掉本地已经获得的变量
//        Set<String> requestVarSets = Sets.difference(varCodes, varContextMap.keySet());
        Set<String> requestVarSets = new HashSet<>(varCodes);
        Map<String, Object> varResult = new HashMap<>();
        JSONObject varTransferRequest;
        if (requestVarSets.size() > 0) {
            // 构造请求参数
            varTransferRequest = new JSONObject();
            varTransferRequest.put(DATA_TRANSFER_VAR_KEY, requestVarSets);
            varTransferRequest.put(DATA_TRANSFER_VAR_CONTEXT_KEY, varContextMap);

            // 发起请求
            long begin = System.currentTimeMillis();
            try {
                String responseData = okHttpClientManage.post(varTransferRequest.toJSONString(), OKHttpClientManage.MEDIATYPE_JSON);
                if (StringUtils.isBlank(responseData)) {
                    throw new XDecisionDataException(XDecisionDataExceptionType.DATA_TRANSFER_RESPONSE_EMPTY, "请求dataTransfer结果为空! inputParam: " + varTransferRequest.toJSONString());
                }
                long end = System.currentTimeMillis();
                long elementDuration = end - begin;
                LOGGER.info("请求变量带过去的 varContextMap = " + varContextMap);
                LOGGER.info("变量获取时间 = " + elementDuration + " MillSeconds");
                varResult = JSONObject.parseObject(responseData, Map.class);
                LOGGER.info("请求返回：variableResult = " + varResult);
                return varResult;
            } catch (SocketTimeoutException e) {
                LOGGER.error("获取dataTransfer 抽象数据源变量连接超时异常, varTransferRequest = " + varTransferRequest.toJSONString(), e);
            } catch (Exception e) {
                LOGGER.error("获取dataTransfer 抽象数据源变量异常, varTransferRequest = " + varTransferRequest.toJSONString(), e);
                throw new XDecisionDataException(XDecisionDataExceptionType.DATA_TRANSFER_RESPONSE_ERROR, "请求DataTransfer异常! varCodes:{} " + JSONObject.toJSONString(varCodes) + " inputParam: " + varTransferRequest.toJSONString(), e);
            }

        } else {
            LOGGER.info("待请求的变量集合为空");
        }
        return varResult;
    }


    public JSONObject standardHttpResponse(VarInterfaceInfoVO interfaceInfo, ExecutorType execorType) {

        if (null == execorType) {
            execorType = ExecutorType.SYNC;
        }
        String response = null;
        String requestBody;
        String requestUrl = interfaceInfo.getUrl();
        int connectTimeout = interfaceInfo.getConnectTimeout() == null ? 4000 : interfaceInfo.getConnectTimeout();
        int readTimeout = interfaceInfo.getReadTimeout() == null ? 4000 : interfaceInfo.getReadTimeout();
        Map<String, Object> inputParam = buildInputFromInterfaceInfoVO(interfaceInfo);

        // 请求参数中的变量赋值
        requestBody = setRequestBodyParams(interfaceInfo.getRequestBody(), inputParam);

        // 设置请求头
        Map headers = JSONObject.parseObject(interfaceInfo.getRequestHeaders(), Map.class);

        okHttpClientManage = OKHttpClientManage.getOkHttpClientManage(requestUrl, connectTimeout, readTimeout);
        if (HttpMethod.POST.name().equals(interfaceInfo.getMethod())) {
            // 发送请求
            if (ExecutorType.SYNC == execorType) {
                try {
                    response = okHttpClientManage.post(requestBody, OKHttpClientManage.MEDIATYPE_JSON, headers);
                    if (StringUtils.isBlank(response)) {
                        LOGGER.error("gatewayResponse is empty, inputParam: {}", JSONObject.toJSONString(inputParam));
                        throw new XDecisionDataException(XDecisionDataExceptionType.DATA_SYNC_REQUEST_GATEEAY_EMPTY_ERROR, "同步post请求外部数据源 返回值为空！");
                    }
                    return JSONObject.parseObject(response);
                } catch (Exception e) {
                    throw new XDecisionDataException(XDecisionDataExceptionType.DATA_SYNC_REQUEST_GATEEAY_ERROR, "同步post外部数据源 请求异常!", e);
                }

            } else {
                LOGGER.info("Async vo gateway, inputParam: {}", JSONObject.toJSONString(inputParam));
            }
            LOGGER.info("[Post请求 StandardHttp 接口源完成] url: {},requestMethod: {}, vo: {}, response: {}", requestUrl, interfaceInfo.getMethod(), requestBody, response);

        } else if (HttpMethod.GET.name().equals(interfaceInfo.getMethod())) {
            // 封装uri地址路径变量
            Map<String, String> uriVariables = new HashMap<>();
            if (StringUtils.isNotBlank(requestBody)) {
                uriVariables = JSONObject.parseObject(requestBody, Map.class);
            }
            if (ExecutorType.SYNC == execorType) {
                try {
                    response = okHttpClientManage.get(headers, uriVariables);
                    if (StringUtils.isBlank(response)) {
                        LOGGER.error("gatewayResponse is empty, inputParam: {}", JSONObject.toJSONString(inputParam));
                        throw new XDecisionDataException(XDecisionDataExceptionType.DATA_SYNC_REQUEST_GATEEAY_EMPTY_ERROR, "同步get请求外部数据源 返回值为空!");
                    }
                    return JSONObject.parseObject(response);
                } catch (Exception e) {
                    throw new XDecisionDataException(XDecisionDataExceptionType.DATA_SYNC_REQUEST_GATEEAY_ERROR, "同步get请求外部数据源 请求异常!", e);
                }
            } else {
                LOGGER.info("Async get vo gateway, inputParam: {}", JSONObject.toJSONString(inputParam));
            }
            LOGGER.info("[Get请求 StandardHttp 接口源完成] url: {},requestMethod: {}, vo: {}, response: {}", requestUrl, interfaceInfo.getMethod(), requestBody, response);

        } else {
            LOGGER.error("接口请求类型不匹配当前 Get or Post请求!");
            throw new XDecisionDataException(XDecisionDataExceptionType.DATA_NO_SUCH_REQUEST_ERROR, "no such type vo for: " + interfaceInfo.getMethod());
        }
        return JSONObject.parseObject(response);
    }


    private String setRequestBodyParams(String requestBody, Map<String, Object> inputParam) {
        if (StringUtils.isBlank(requestBody) || inputParam == null) {
            return "";
        }
        // 添加动态参数
        Pattern pattern = Pattern.compile("\\{[a-zA-Z0-9_\u4e00-\u9fa5()（）-]+\\}");
        Matcher matcher = pattern.matcher(requestBody);
        while (matcher.find()) {
            String matchStr = matcher.group(0);
            String param = matchStr.replace("{", "").replace("}", "");
            // 动态参数从变量池获取
            requestBody = requestBody.replace(matchStr, String.valueOf(inputParam.get(param)));
        }
        return requestBody;
    }


    public Map<String, Object> buildInputFromInterfaceInfoVO(VarInterfaceInfoVO interfaceInfo) {
        Map<String, Object> inputParam = Maps.newHashMap();
        String bindParam = interfaceInfo.getBindParam();
        if (StringUtils.isNotBlank(bindParam)) {
            JSONObject param = JSON.parseObject(bindParam);
            JSONArray dictVariable = param.getJSONArray("dictVariable");
            for (int i = 0; i < dictVariable.size(); i++) {
                JSONObject jsonObject = dictVariable.getJSONObject(i);
                Object value = DictVariableUtils.getValueFromJsonObject(jsonObject);
                inputParam.put(jsonObject.getString("key"), value);
            }
            JSONArray variable = param.getJSONArray("variable");
            for (int i = 0; i < variable.size(); i++) {
                JSONObject jsonObject = variable.getJSONObject(i);
                if (!inputParam.containsKey(jsonObject.getString("key"))) {
                    inputParam.put(jsonObject.getString("key"), jsonObject.get("value"));
                }
            }

        }
        LOGGER.info("build bind inputParam: {} ", JSONObject.toJSONString(inputParam));
        return inputParam;
    }


    /**
     * 解析接口变量
     */
    public String interfaceParseVariable(String parseStr, String jsonStr) {
        JSONObject json = null;
        try {
            json = JSONObject.parseObject(jsonStr);
        } catch (Exception e) {
            JSONArray jsonArray = JSONArray.parseArray(jsonStr);
            json = jsonArray.getJSONObject(0);
        }

        if (parseStr.contains(".[]")) {
            parseStr = parseStr.replace(".[]", "[]");
        }
        String[] strArr = parseStr.split("\\.");
        for (int i = 0; i < strArr.length - 1; i++) {
            if (strArr[i].contains("[]")) {
                strArr[i] = strArr[i].replace("[]", "");
                JSONArray jsonArray = json.getJSONArray(strArr[i]);
                json = jsonArray.getJSONObject(0);
            } else {
                json = json.getJSONObject(strArr[i]);
            }
        }
        String value = null;
        if (json != null) {
            value = json.getString(strArr[strArr.length - 1]);
        }
        return value;
    }


}
